#! env python
# -*- coding: utf-8 -*-
from nevow import appserver, inevow, loaders, athena, static, guard, rend, tags as T
from twisted.application import service, internet
from twisted.internet import reactor, defer
from twisted.python import failure
from zope.interface import implements
import os, os.path

class FrontPage(rend.Page):
    implements(inevow.IResource)
	
    def __init__(self, webroot):
        super(ClientLogin, self).__init__()
        self.webroot = webroot
        self.docFactory = loaders.xmlfile(self.webroot + '/front.html')
		
    def locateChild(self, ctx, segments):
        print segment[0]
        if(segments[0] == 'client.css'):
            return static.File(self.webroot + '/client.css'), ()
        return self, ()
	
    def render_loginaction(self, ctx, data):
        return Guard.LOGIN_AVATAR


class AuthenticatedClient(rend.Page):
    implements(inevow.IResource)
	
    def __init__(self, webroot, user, login_code):
        super(AuthenticatedClient, self).__init__()
        self.webroot = webroot
        self.user = user
        self.login_code = login_code

    def locateChild(self, ctx, segments):
        if(segments[0]):
            possible_file = os.path.join(self.webroot, '/'.join(segments))
            if(os.access(possible_file, os.R_OK)):
                return static.File(possible_file), ()
            if(segments[0] == 'edit' and len(segments) > 1 ):
                if(segments[1] == 'entity'):
                    return EntityEditor(self.webroot, self.user), segments[2:]
		
            if(len(segments) == 1):
                self.login_code(self.user)
            client = ClientInterface(self.webroot, self.user)
            client.notifyOnDisconnect().errback = self.logout
            return client, segments
	
    def logout(self, *args, **kwargs):
        reactor.callLater(1, actions.logout_code, self.user)


class ClientInterface(athena.LivePage):	
    def __init__(self, webroot, user):
        super(ClientInterface, self).__init__()
        self.webroot = webroot
        self.user = user
        self.docFactory = loaders.xmlfile(self.webroot + '/client-interface.xml')
	
    def render_ClientConnector(self, ctx, data):
        f = ClientConnector(self.user)
        f.setFragmentParent(self)
        return ctx.tag[f]
	
    def locateChild(self, ctx, segments):
        if(segments[0]):
            return super(ClientInterface, self).locateChild(ctx, segments)
        return self, ()
	
    def action_call(self, ctx, requestId, method, objectID, args, kwargs):
        auth.user_activate(self.user)
        
        localObj = self._localObjects[objectID]
        
        try:
            func = localObj.locateMethod(ctx, method)
        except AttributeError:
            result = defer.fail(NoSuchMethod(objectID, method))
        else:
            result = defer.maybeDeferred(func, *args, **kwargs)
            
            def _cbCall(result, user):
                auth.user_activate(user)
                success = True
                if isinstance(result, failure.Failure):
                    internal_error = result.trap(errors.UserError, errors.EngineError)
                    if(internal_error == errors.UserError):
                        print "User caused exception: " + repr(result.value)
                        self.user._connection.write('<span class="error">' + str(result.value) + '</span>', None, None)
                        return
                    elif(internal_error == errors.EngineError):
                        print self.user, "raised", str(result.value)
                        self.user._connection.write('<span class="error">' + str(result.value) + '</span>', None, None)
                        return
                    log.msg("Sending error to browser:")
                    log.err(result)
                    success = False
                    
                    if result.check(LivePageError):
                        result = (
                            result.value.jsClass,
                            result.value.args)
                    else:
                        result = (
                            u'Divmod.Error',
                            [u'%s: %s' % (
                                    result.type.__name__.decode('ascii'),
                                    result.getErrorMessage().decode('ascii'))])
			message = (u'respond', (unicode(requestId), success, result))
			self.addMessage(message)
			auth.user_deactivate()
                        
                        result.addBoth(_cbCall, self.user)
                        
                        auth.user_deactivate()


class ClientConnector(athena.LiveElement):
    jsClass = u'innerspace.ClientConnector'
    docFactory = loaders.stan(T.div(render=T.directive('liveElement'))[
            T.div(id='client-connector')
            ])
    
    def __init__(self, user, *args, **kwargs):
        self.user = user
        self.user.set_connection(actions.RemoteWrapper(self))
        self.registry = auth.get_registry()
        
    def parse(self, command):
        actions.parse(self.user, auth.get_registry(), command)
    athena.expose(parse)

    def req_entity_editor(self, id):
        obj = self.registry.get(str(id))
        return editors.edit_entity(self.user, obj, request_id)
    athena.expose(req_entity_editor)
		
class EntityEditor(athena.LivePage):
    def __init__(self, webroot, user):
        super(EntityEditor, self).__init__()
        self.webroot = webroot
        self.user = user
        self.docFactory = loaders.xmlfile(self.webroot + '/entity-editor.xml')
	
    def locateChild(self, ctx, segments):
        if(segments):
            return super(EntityEditor, self).locateChild(ctx, segments)
        return self, ()
